package com.service.order;

import com.domain.HttpResponse;
import com.domain.ex.BizException;
import com.domain.ex.Codes;
import com.domain.myenum.DeliveryTypeEnum;
import com.domain.myenum.OrderStatusEnum;
import com.domain.myenum.PayStatusEnum;
import com.domain.myenum.ProductUnitEnum;
import com.domain.page.Paginator;
import com.dto.CompanyExtDto;
import com.dto.OrderExtDto;
import com.dto.statistic.StatisticOutDto;
import com.dto.statistic.StatisticOutputDto;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.handler.email.Email;
import com.handler.email.EmailHandler;
import com.mapper.generator.ShIncomeWaterMapper;
import com.mapper.generator.ShOrderMapper;
import com.mapper.generator.ShProductMapper;
import com.mapper.self.CompanyMapper;
import com.mapper.self.IncomeWaterMapper;
import com.mapper.self.OrderMapper;
import com.mapper.self.ProductMapper;
import com.pojo.ShCompany;
import com.pojo.ShIncomeWater;
import com.pojo.ShOrder;
import com.pojo.ShProduct;
import com.utils.DateUtils;
import com.utils.RandomUtils;
import com.utils.ValidatorUtils;
import org.apache.commons.lang.StringUtils;
import org.omg.PortableInterceptor.INACTIVE;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * Created by Administrator on 2016/2/18 0018.
 */
@Service
public class OrderServiceImpl implements OrderService {


    @Autowired
    private ShOrderMapper shOrderMapper;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private EmailHandler emailHandler;
    @Autowired
    private CompanyMapper companyMapper;
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private ShIncomeWaterMapper shIncomeWaterMapper;
    @Autowired
    private IncomeWaterMapper incomeWaterMapper;

    @Override
    public Object add(int productId, String email, int count, String sendtime, BigDecimal amount, BigDecimal originalCost, Integer deliveryType, String sendAddr, String remark) {
        // - 验证客户资料是否完善：手机号，送货地址
        Date sendDate = addOrderValiate(email, sendtime, deliveryType, sendAddr);
        ShOrder shOrder = new ShOrder();
        shOrder.setCompanyEmail(email);
        shOrder.setProductId(productId);
        shOrder.setCount(count);
        shOrder.setAmount(amount);
        shOrder.setOriginalCost(originalCost);
        shOrder.setPayStatus(String.valueOf(PayStatusEnum.NotPay.getCode()));
        shOrder.setStatus(String.valueOf(OrderStatusEnum.Wait.getCode()));
        shOrder.setDeleted(0);
        shOrder.setCreatetime(new Date());
        shOrder.setSendtime(sendDate);
        // - 设置Bigdecimal的精度
        shOrder.getAmount().setScale(2);
        // - 设置订单编号
        shOrder.setOrderNo(RandomUtils.getOrderCode());
        shOrder.setDeliveryType(deliveryType.toString());
        shOrder.setSendAddr(sendAddr);
        shOrder.setRemark(remark);
        shOrderMapper.insertSelective(shOrder);
        OrderExtDto orderExtDto = orderMapper.queryByOrderNo(shOrder.getOrderNo());
        mailNotifySalersOrderStatusChanged(orderExtDto, "新订单通知");
        return HttpResponse.create(Codes.OK, "", shOrder.getOrderNo());
    }

    private Date addOrderValiate(String email, String sendtime, Integer deliveryType, String sendAddr) {
        if (StringUtils.isBlank(email)) {
            throw BizException.create(Codes.SystemDeclare, "邮箱为空");
        }
        ShCompany shCompany = companyMapper.queryByEmail(email);
        if (shCompany == null) {
            throw BizException.create(Codes.SystemDeclare, "没有查询到客户信息");
        }
        if (!ValidatorUtils.validatorMobile(shCompany.getPhone())) {
            throw BizException.create(Codes.SystemDeclare, "没有查询到手机号");
        }
        Date sendDate = DateUtils.parseDate("yyyy-MM-dd HH:mm:ss", sendtime + ":00");
        if (sendDate.compareTo(new Date()) < 0) {
            throw BizException.create(Codes.SystemDeclare, "取货时间不得早于当前时间");
        }
        if (deliveryType == null) {
            throw BizException.create(Codes.SystemDeclare, "选择取货方式");
        }
        if (deliveryType == 2) {
            // - 送货上门
            if (StringUtils.isBlank(sendAddr)) {
                throw BizException.create(Codes.SystemDeclare, "填写送货地址");
            }
        }
        return sendDate;
    }

    private void mailNotifySalersOrderStatusChanged(OrderExtDto orderExtDto, String subject) {
        if (StringUtils.isNotBlank(orderExtDto.getShopEmail())) {
            orderNotifyEmail(orderExtDto, subject, Sets.newHashSet(orderExtDto.getShopEmail()));
        }
    }


    /**
     * 订单邮件通知
     *
     * @param orderExtDto 订单信息
     * @param subject     邮件主题
     */
    @Override
    public void orderNotifyEmail(OrderExtDto orderExtDto, String subject, Set<String> emailSet) {
        if (orderExtDto == null) {
            return;
        }
        // - 客户信息
        ShCompany shCompany = companyMapper.queryByEmail(orderExtDto.getEmail());
        String[] to = emailSet.toArray(new String[emailSet.size()]);
        Map<String, Object> map = Maps.newHashMap();
        map.put("buyer", shCompany.getName());
        map.put("mobile", shCompany.getPhone());
        map.put("deliveryType", DeliveryTypeEnum.queryStatusVal(Integer.valueOf(orderExtDto.getDeliveryType())));
        map.put("goodName", orderExtDto.getProductName());
        map.put("price", orderExtDto.getPrice() + "元/" + ProductUnitEnum.queryStatusVal(Integer.parseInt(orderExtDto.getUnit())));
        map.put("count", orderExtDto.getCount() + "/" + ProductUnitEnum.queryStatusVal(Integer.parseInt(orderExtDto.getUnit())));
        map.put("shopName", orderExtDto.getShopName());
        map.put("amount", orderExtDto.getAmount() + "元");
        map.put("remark", StringUtils.isBlank(orderExtDto.getOrderRemark()) ? "无" : orderExtDto.getOrderRemark());
        map.put("sendTime", DateUtils.getFormatDate("yyyy-MM-dd HH:mm:ss", orderExtDto.getSendtime()));
        map.put("reason", orderExtDto.getReason());
        map.put("address", orderExtDto.getSendAddr());
        map.put("subject", subject);
        Email e = new Email();
        e.setTo(to);
        e.setSubject(subject);
        e.setEnableHtml(Boolean.TRUE);
        if (Integer.parseInt(orderExtDto.getDeliveryType()) == DeliveryTypeEnum.GetBySelf.getCode()) {
            e.setTemplate("BookOrderTemplate.ftl");
        }
        if (Integer.parseInt(orderExtDto.getDeliveryType()) == DeliveryTypeEnum.SendHome.getCode()) {
            e.setTemplate("SendOrderTemplate.ftl");
        }
        e.setMap(map);
        emailHandler.asyncSendMail(e);
    }


    @Override
    public Object list(int page, int limit, String email) {
        if (page > 0) {
            page = page - 1;
        }
        List<OrderExtDto> list = orderMapper.list(page * limit, limit, email);
        Paginator paginator = Paginator.instance(orderMapper.count(email), list);
        paginator.setPage(page + 1);
        return paginator;
    }


    @Override
    public Object orderManage(int page, int limit, String email) {
        if (page > 0) {
            page = page - 1;
        }
        List<OrderExtDto> list = orderMapper.orderManage(page * limit, limit, email);
        Paginator paginator = Paginator.instance(orderMapper.orderMgrCount(), list);
        paginator.setPage(page + 1);
        return paginator;
    }

    @Override
    public Object dealOrder(String orderNo, Integer status, String reason) {
        if (StringUtils.isBlank(orderNo)) {
            return HttpResponse.create(Codes.ParamError, "没有查询到订单");
        }
        // - 订单状态不可逆转验证
        OrderExtDto orderExtDto = orderMapper.queryByOrderNo(orderNo);
        if (orderExtDto == null) {
            return HttpResponse.create(Codes.ParamError, "没有查询到订单");
        }
        if (StringUtils.isNotBlank(orderExtDto.getStatus())) {
            if (status.intValue() == OrderStatusEnum.Canceled.getCode()) {
                // - 取消订单
                if (Integer.parseInt(orderExtDto.getStatus()) != OrderStatusEnum.Wait.getCode()) {
                    // - 订单不出在等待状态不可取消
                    return HttpResponse.create(Codes.ParamError, "订单编号：" + orderExtDto.getOrderNo() + "，不可撤单");
                }
            }
            if (status.intValue() == OrderStatusEnum.Refused.getCode()) {
                // - 拒绝订单
                if (Integer.parseInt(orderExtDto.getStatus()) != OrderStatusEnum.Wait.getCode()) {
                    // - 订单不出在等待状态不可拒绝
                    return HttpResponse.create(Codes.ParamError, "订单编号：" + orderExtDto.getOrderNo() + "，不可拒绝");
                }
            }
            if (status.intValue() <= Integer.parseInt(orderExtDto.getStatus())) {
                return HttpResponse.create(Codes.ParamError, "订单编号：" + orderExtDto.getOrderNo() + "，状态不可逆转");
            }
        }
        int ret = orderMapper.updateOrderStatus(Lists.newArrayList(orderNo), status, reason);
        // - 完成订单
        if (status.intValue() == OrderStatusEnum.Finished.getCode()) {
            // - 如果订单状态变成完成，将积分累加
            companyMapper.incrUserCredits(orderExtDto.getEmail(), orderExtDto.getAmount());
            // - 商品销量增加，库存减少
            productMapper.updateProductSalesAndInventory(orderExtDto.getCount(), orderExtDto.getProductId());
            // - 记录我的和推荐人的收益流水
            BigDecimal income = orderExtDto.getAmount().subtract(orderExtDto.getOriginalCost()).multiply(BigDecimal.valueOf(0.1)).setScale(2, BigDecimal.ROUND_HALF_UP);
            recordIncomeWater(orderExtDto.getCompanyName(), orderExtDto.getEmail(), income, orderExtDto.getProductName(), orderExtDto.getProductId(), orderExtDto.getShopName());
        }
        // - 订单状态变更，邮件通知
        orderExtDto.setStatus(status.toString());
        orderExtDto.setReason(reason);
        // - 邮件收信人
        Set<String> emails = Sets.newHashSet();
        if (status.intValue() == OrderStatusEnum.Accepted.getCode() || status.intValue() == OrderStatusEnum.Refused.getCode()) {
            // - 商家接单/拒绝发邮件通知买家
            emails.add(orderExtDto.getEmail());
            orderNotifyEmail(orderExtDto, "订单状态变更：" + OrderStatusEnum.queryStatusVal(Integer.parseInt(orderExtDto.getStatus())), emails);
        }
        if (status.intValue() == OrderStatusEnum.Canceled.getCode()) {
            // - 用户撤单，邮件通知卖家
            mailNotifySalersOrderStatusChanged(orderExtDto, "用户撤单通知");
        }
        return HttpResponse.OK();
    }

    // - 收益记录流水，同时记录自己和推荐人
    public void recordIncomeWater(String buyer, String email, BigDecimal income, String productName, Integer productId, String shopName) {
        CompanyExtDto companyExtDto = companyMapper.queryCompanyExtByEmail(email);
        Date date = new Date();
        if (StringUtils.isBlank(companyExtDto.getReferralEmail())) {
            // - 没有推荐人
            ShIncomeWater shIncomeWater = new ShIncomeWater();
            shIncomeWater.setCreateTime(date);
            shIncomeWater.setEmail(email);
            shIncomeWater.setProductId(productId);
            shIncomeWater.setIncome(income);
            shIncomeWater.setReason("消费[" + productName + "]产生收益");
            shIncomeWaterMapper.insertSelective(shIncomeWater);
            companyMapper.addIncome(email,income);
        } else {
            List<ShIncomeWater> incomeWaters = Lists.newArrayList();
            ShIncomeWater shIncomeWater = new ShIncomeWater();
            shIncomeWater.setCreateTime(date);
            shIncomeWater.setEmail(email);
            shIncomeWater.setProductId(productId);
            shIncomeWater.setIncome(income.multiply(BigDecimal.valueOf(0.8)).setScale(2, BigDecimal.ROUND_HALF_UP));
            shIncomeWater.setReason("消费[" + productName + "]产生收益");
            incomeWaters.add(shIncomeWater);
            ShIncomeWater shIncomeWater1 = new ShIncomeWater();
            shIncomeWater1.setCreateTime(date);
            shIncomeWater1.setProductId(productId);
            shIncomeWater1.setIncome(income.multiply(BigDecimal.valueOf(0.2)).setScale(2, BigDecimal.ROUND_HALF_UP));
            shIncomeWater1.setEmail(companyExtDto.getReferralEmail());
            shIncomeWater1.setReason("邀请人：" + buyer + "，消费：" + productName + "提成");
            incomeWaters.add(shIncomeWater1);
            incomeWaterMapper.batchInsert(incomeWaters);
            companyMapper.addIncome(email,income.multiply(BigDecimal.valueOf(0.8)).setScale(2, BigDecimal.ROUND_HALF_UP));
            companyMapper.addIncome(companyExtDto.getReferralEmail(),income.multiply(BigDecimal.valueOf(0.2)).setScale(2, BigDecimal.ROUND_HALF_UP));
            // - 邮件通知推荐人
            notifyReferralIncomeChangeByEmail(shIncomeWater1.getEmail(), shIncomeWater1.getIncome(), companyExtDto.getReferralName(), productName, shopName, date);
        }
    }


    // - 邮件通知推荐人收益更新
    @Override
    public void notifyReferralIncomeChangeByEmail(String email, BigDecimal income, String referralName, String productName, String shopName, Date time) {
        String[] to = new String[1];
        to[0] = email;
        Email e = new Email();
        e.setTo(to);
        e.setSubject("收益到账通知");
        e.setEnableHtml(Boolean.TRUE);
        Map<String, Object> map = Maps.newHashMap();
        map.put("income", "1.50元");
        map.put("source", "alisa.wang");
        map.put("shop", "老马家面馆");
        map.put("good", "一碗香");
        map.put("time", DateUtils.getFormatDate(null, time));
        e.setMap(map);
        e.setTemplate("incomeTemplate.ftl");
        emailHandler.asyncSendMail(e);
    }

    @Override
    public StatisticOutDto statisticSales() {
        StatisticOutDto dto = new StatisticOutDto();
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        Object email = request.getSession().getAttribute("email");
        if (email == null) {
            return dto;
        }
        List<String> xAixs = productMapper.queryProductNameByShopEmail(email.toString());
        List<Integer> yAixs = Lists.newArrayList();
        if (CollectionUtils.isEmpty(xAixs)) {
            return dto;
        }
        dto.setxAixs(xAixs);
        List<StatisticOutputDto> list = orderMapper.statisticSales(email.toString());
        if (CollectionUtils.isEmpty(list)) {
            for (String xAix : xAixs) {
                yAixs.add(0);
            }
            dto.setyAixs(yAixs);
            return dto;
        }
        Map<String, Object> map = Maps.newHashMap();
        for (String xAix : xAixs) {
            map.put(xAix, 0);
        }
        for (StatisticOutputDto outputDto : list) {
            if (StringUtils.isNotBlank(outputDto.getName())) {
                map.put(outputDto.getName(), outputDto.getData());
            }
        }
        for (String xAix : xAixs) {
            yAixs.add(Integer.valueOf(map.get(xAix).toString()));
        }
        dto.setxAixs(xAixs);
        dto.setyAixs(yAixs);

        return dto;
    }
}
